home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr10
/
bagtag2.zip
/
CTAGS.CB
< prev
next >
Wrap
Lisp/Scheme
|
1992-11-17
|
17KB
|
502 lines
/****************************************************************************
*
* ctags.cb 17Nov92
*
* File: ctags.cb 8/24/85
* Written by: Yellow Pig XVII
* Modified by: The Shaman 08/07/90
* Modified by: BAG 22Oct92
*
* Contains entries:
* _init
* tag
* ctag
* locate_in_file
* parse_tag_line
*
* BRIEF macros to do vi-like tag. Assumes the existence of a file
* called (TAGFILE) which can be created using the "ctags" utility. If
* this file doesn't exist, tag is simply reported as "Not found."
* The format of each line of the tags file must be:
*
* tagword filename ?<pattern>?
*
* This is the normal output produced by the Unix utility "ctags".
*
* For those unfamiliar with tagging, it is really useful. If you
* create a tags file for all your C source files you can locate the
* file and line where a given function is declared when you're in
* the editor, even if that function is declared in a different
* source file from the one you are editing. Tagging will move you
* to that line in that file.
*
* tag <identifier>:
* To use these BRIEF macros, you can call "tag" directly as a
* command. It will ask you to enter a tag. Give the name of the
* function you are searching for (case sensitivity will depend on
* the current setting in your editing session). Or you can assign
* the macro "ctag" to a key. If you do this, you can place the
* cursor anywhere on the name of a function you wish to tag to
* (presumably an occurrence of it where it is being called, but
* this is not necessary -- you can tag to a function if you are
* already there!!) and hit the key you assigned.
*
* tag { /first | /last | /next | /prev | /clear }
* Move to the corresponding file in the chronological list of
* identifiers tagged to, or clear the list.
*
* ctag:
* Checks to make sure cursor is on a valid function name. A valid
* function name is considered to be any string of alphanumeric
* characters (including the underscore) which begins with a letter.
*
* If the tag is invalid, the cursor position remains the same.
* Otherwise the full word is read and passed to "tag".
*
* Macro goto.cb hooks these into the same Alt-g key normally used for
* goto_line:
* if a numeric value is entered, it acts like goto_line
* if a non-numeric string "foo" is entered, it acts like tag foo
* if Enter is hit, it acts like ctag
* Esc kills the command
*
* Changes/Additions by Michael Denio 5/15/90
* ------------------------------------------
* The program now looks for all CTAGS.TAG files specified in directories
* in the CTAGS environment variable. It first looks in the current
* directory. Example: set CTAGS=C:\;N:\LIB\SRC;
* Place the following in your initials file:
* (autoload "ctags" "ctag" "tag")
* You can then assign a key to ctag and tag macros.
*
* Changes/Additions by The Shaman 08/07/90
* ----------------------------------------
* Added TAGFILE define when searching the current path.
* Changed path search so that it is done sequentially as in DOS
* rather than by reading contents of all tag files into a
* buffer before doing a search on the tag.
* Added appropriate message displays while tagging.
* Made read_word function and string searches more efficient.
*
* Changes/Additions by Edward Diener 7/14/92 Compuserve 70304,2632
* ----------------------------------------------------------------
* (Taken from ctags5.zip from Borland-Brief Forum on CompuServe)
* He added something on the order of keeping a list of files tagged to,
* allowing one to page forward and backward through the list. BUT,
* he had some scheme of FROM and TO positions and stopping at this or
* that, which makes no sense to me. But I'll steal the underlying idea.
* See change notes below and doc above re
* tag { /first | /last | /next | /prev | /clear }
* in addition to the basic
* tag <identifier>
*
* Things to add, think about, etc.
* --------------------------------
* "Automatically" (i.e., under certain circumstances) call ctags.com to
* generate the tag file?
*
* Copyright (c) 1992 B. Goldstein -- Pequod Software
*
* Change History
* Date Who What
* ------- --- ---------------------
* 22Oct92 BAG Dropped The Shaman's thing about stripping braces
* from search pattern (I think he should have done the
* escape-re thing that I added to ctags.c)
* Changed name of macro from tags.cb to ctags.cb
* 22Oct92 BAG Dropped cch from read_word, etc.
* 22Oct92 BAG Bug in find_word, in search_fwd pattern
* 24Oct92 BAG read_word identifier scan included one too many characters
* 27Oct92 BAG Added /first | /last | /next | /prev | /clear options to tag
* 28Oct92 BAG Dropped file name from messages (it's always TAGFILE); left
* pathname
* 28Oct92 BAG Replaced ctag search (let's stay on same line, at least)
* 28Oct92 BAG And that means there's not much need for read_word at all
* 28Oct92 BAG And locate_in_file doesn't need any argument, since it uses
* the found file name locally
* 28Oct92 BAG But since tag lines need to be parsed for chaining and for
* original tagging, added parse_tag_line routine
* 17Nov92 BAG Altered search for TAGFILE: First current directory, then
* directory of file being edited, then CTAGS path
* 17Nov92 BAG Added scan of keyboard to abort scan between directories
*
****************************************************************************/
/* Definitions */
#define TAGENV "CTAGS" // CTAGS environment variable
#define TAGFILE "CTAGS.TAG" // CTAGS filename
//---------------------------------------------------------------------------
/* Info for moving around tagged files */
int tag_chain_buffer; // Buffer for holding tag chaining info
int tag_chain_line; // Current line in buffer
//---------------------------------------------------------------------------
/* Prototypes */
void _init (void);
void tag (string);
void ctag (void);
void locate_in_file (void);
void parse_tag_line (string tag_line, string the_file, string pattern);
string GetIdentifier (~string);
//---------------------------------------------------------------------------
/* External references */
extern center_line (void);
/***************************************************************************/
/* _init */
/* */
/* Create system buffer for tag chaining */
/* */
void _init (void)
{
tag_chain_buffer = create_buffer ("tagsave", NULL, 1); // SYSTEM_BUFF
return;
}
//---------------------------------------------------------------------------
/* tag */
/* */
/* Looks in tags file for given tag, gets the filename and search */
/* pattern to use in locating the tag, edits the given file and */
/* searches for the pattern. If the tag isn't found, reports an */
/* error. There is no error checking in this macro for a valid */
/* function name (tag). This macro will most often be used in */
/* conjunction with the "ctag" macro which does this error checking. */
/* */
/* If operand is one of { /first | /last | /next | /prev | /clear } */
/* then it moves to the corresponding file in the chronological list */
/* of identifiers tagged to, or it clears that list. */
void tag (~string)
{ string tagstr, the_file, pattern, tag_path, tag_file, tag_dir;
string file_dir, curr_dir;
int buf, tagbuf, semi_spot, found = 0;
global tagstr;
// Get tag to search for
if (! get_parm (0, tagstr, "Enter tag: ", NULL, tagstr))
return;
buf = inq_buffer ();
//-----------------------------------------------------------------------
if (substr (tagstr, 1, 1) == "/")
{ // It's a navigation command
string tag_line;
int chain_lines;
if (! tag_chain_buffer)
{ error ("Couldn't install tag chaining.");
return;
}
set_buffer (tag_chain_buffer);
end_of_buffer ();
move_abs (0,1);
tag_line = read ();
inq_position (chain_lines);
if (tag_line == "\n")
chain_lines--;
if (! chain_lines)
{ error ("Nothing in tag chain.");
set_buffer (buf);
return;
}
tagstr = lower (substr (tagstr, 2));
tagstr = ltrim (trim (tagstr));
switch (tagstr)
{ case "first":
case "f":
tag_chain_line = 1;
move_abs (tag_chain_line, 1);
tag_line = read ();
found = 1;
case "last":
case "l":
tag_chain_line = chain_lines;
move_abs (tag_chain_line, 1);
tag_line = read ();
found = 1;
case "next":
case "n":
if (tag_chain_line == chain_lines)
error ("No next in tag chain.");
else
{ tag_chain_line++;
move_abs (tag_chain_line, 1);
tag_line = read ();
found = 1;
}
case "prev":
case "p":
if (tag_chain_line == 1)
error ("No prev in tag chain.");
else
{ if (tag_chain_line == 0)
tag_chain_line = chain_lines;
else
tag_chain_line--;
move_abs (tag_chain_line, 1);
tag_line = read ();
found = 1;
}
case "clear":
case "c":
top_of_buffer ();
drop_anchor (1); // NORMAL_MARK
end_of_buffer ();
delete_block ();
tag_chain_line = 0;
message ("Tag chain has been cleared.");
default:
error ("/%s is not a valid tag operand", tagstr);
}
// go back to user's buffer
set_buffer (buf);
if (found)
{ // tag_line has info for switching to desired file
parse_tag_line (tag_line, the_file, pattern);
edit_file (the_file);
end_of_buffer ();
if (search_back (pattern) <= 0)
error ("Couldn't find \"%s\"",
substr (pattern, 2, strlen (pattern) - 2));
else
center_line ();
}
return;
}
//-----------------------------------------------------------------------
// Get directory stuff for searching
inq_names (file_dir);
getwd (NULL, curr_dir);
semi_spot = rindex (file_dir, "\\");
file_dir = substr (file_dir, 1, semi_spot-1);
// Set up buffer for tag files
tagbuf = create_buffer ("tags", NULL, 1);
set_buffer (tagbuf);
tag_file = TAGFILE;
// If one exists, read the TAGFILE file from the current directory
if (exist(TAGFILE))
{ getwd (NULL, tag_dir);
message ("Looking for tag %s in %s", tagstr, tag_dir);
read_file (TAGFILE);
move_abs (1, 1);
if (search_fwd ("<" + tagstr + "[\t ]") > 0)
{ locate_in_file ();
if (tagbuf != buf)
delete_buffer (tagbuf);
return;
}
else
{ message ("Tag %s not found in %s", tagstr, tag_dir);
delete_buffer (tagbuf);
tagbuf = create_buffer ("tags", NULL, 1);
set_buffer (tagbuf);
}
}
// Failing that, look in directory of file being edited (if different)
// Failing that, search for TAGFILE files in the TAGENV env variable path
tag_path = inq_environment (TAGENV);
if (file_dir != curr_dir)
tag_path = file_dir + ";" + tag_path;
// Search tag_path
if (substr(tag_path, strlen(tag_path), 1) != ";")
tag_path = tag_path + ";";
if (tag_path != "")
{ while (semi_spot = index (tag_path, ";"))
{ tag_dir = substr (tag_path, 1, semi_spot - 1);
tag_path = substr (tag_path, semi_spot + 1);
if (substr (tag_dir, strlen (tag_dir), 1) != "\\")
tag_dir = tag_dir + "\\";
message ("Looking for tag %s in %s", tagstr, tag_dir);
if (inq_kbd_char ()) /* see if any keys pressed */
{ read_char (); /* swallow the key */
message ("Aborted search for tag %s before %s",
tagstr, tag_dir);
set_buffer (buf);
if (tagbuf != buf)
delete_buffer (tagbuf);
return;
}
tag_file = tag_dir + TAGFILE;
read_file(tag_file);
move_abs (1, 1);
if (search_fwd ("<" + tagstr + "[\t ]") > 0)
{ locate_in_file ();
found = 1;
break;
}
else
{ message ("Tag %s not found in %s", tagstr, tag_dir);
delete_buffer (tagbuf);
tagbuf = create_buffer ("tags", NULL, 1);
set_buffer (tagbuf);
}
}
}
if (! found)
{ message ("Tag %s not found", tagstr);
set_buffer (buf);
}
if (tagbuf != buf)
delete_buffer (tagbuf);
return;
}
//---------------------------------------------------------------------------
void ctag (void)
{ string tagstr;
tagstr = GetIdentifier ("a-zA-Z0-9_");
if (tagstr == "")
error ("Not on valid identifier.");
else
tag (tagstr);
return;
}
//---------------------------------------------------------------------------
void locate_in_file (void)
{ string tag_line, the_file, pattern;
// We are in the TAGFILE buffer, and will switch to the file-to-be-edited
// at the end of this
tag_line = read (); // save the tag line for the chain file
message ("tag_line = <%s>", tag_line);
// tag_line has info for switching to desired file
// analyze the tag line: "tag file pattern"
parse_tag_line (tag_line, the_file, pattern);
// insert the tag line in place in the chain file
set_buffer (tag_chain_buffer);
tag_chain_line++;
move_abs (tag_chain_line, 1);
insert (tag_line);
// switch to the tagged file
edit_file (the_file);
end_of_buffer ();
// and find the function header
if (search_back (pattern) <= 0)
error ("Couldn't find \"%s\"",
substr (pattern, 2, strlen (pattern) - 2));
else
center_line ();
return;
}
/****************************************************************************
*
* parse_tag_line 28Oct92
*
* tag_line has info for switching to desired file
* we have the line in hand:
* "tagstr the_file pattern"
*
* Returns "the_file" and "pattern"
*
* Change History:
* Date Who What
* ------- --- -------------
* 28Oct92 BAG First draft
*
****************************************************************************/
void parse_tag_line (string tag_line, string the_file, string pattern)
{ int posn;
string loc_the_file, loc_pattern;
// Throw away "tagstr"
posn = search_string ("[\t ]", tag_line);
tag_line = substr (tag_line, posn+1);
// Throw away blanks between "tagstr" and "the_file"
posn = search_string ("[~\t ]", tag_line);
tag_line = substr (tag_line, posn);
// Get "the_file"
posn = search_string ("[\t ]", tag_line);
loc_the_file = substr (tag_line, 1, posn-1);
// Remove it and blanks from it to pattern from what's left of tag_line
tag_line = substr (tag_line, posn+1);
posn = search_string ("[~\t ]", tag_line);
loc_pattern = substr (tag_line, posn);
// Strip off leading "?" and final "?\n" from pattern
loc_pattern = substr (loc_pattern, 2, strlen (loc_pattern) - 3);
// Return the values
put_parm (1, loc_the_file);
put_parm (2, loc_pattern);
return;
}
/************************ end of ctags.cb file *****************************/